precision highp float;

uniform sampler2D u_tex;
uniform vec2 u_screen_size;
uniform float u_radius;
uniform float u_intensity;

varying vec2 v_xy;

#define PI_5 0.62831853071
#define PI_2 1.57079632679
#define PI   3.14159265359
#define PI2  6.28318530718

#define STROKE_SAMPLES 72
#define FILL_SAMPLES 30
#define SHAPE shape_heart
//#define SHAPE shape_star5
//#define USE_STROKE


float sine_i (float x) {
    return 1.0 - cos(x * PI_2);
}
float sine_o (float x) {
    return sin(x * PI_2);
}
float sine_io (float x) {
    x += x;
    float x0 = sine_i(x);
    float x1 = sine_o(x - 1.0);
    return mix(x0 * 0.5, x1 * 0.5 + 0.5, step(1.0, x));
}
float sine_oi (float x) {
    x += x;
    float x0 = sine_o(x);
    float x1 = sine_i(x - 1.0);
    return mix(x0 * 0.5, x1 * 0.5 + 0.5, step(1.0, x));
}


float quad_i (float x) {
    return x * x;
}
float quad_o (float x) {
    x = 1.0 - x;
    return 1.0 - x * x;
}
float quad_io (float x) {
    x += x;
    float x0 = quad_i(x);
    float x1 = quad_o(x - 1.0);
    return mix(x0 * 0.5, x1 * 0.5 + 0.5, step(1.0, x));
}
float quad_oi (float x) {
    x += x;
    float x0 = quad_o(x);
    float x1 = quad_i(x - 1.0);
    return mix(x0 * 0.5, x1 * 0.5 + 0.5, step(1.0, x));
}


float shape_heart (float r, float x, float y) {
    r = 1.5;
    r += pow(abs(x), 2.0) * 0.5;
    r += pow(1.0 - abs(x), 2.0) * sign(y) * 0.8;
    return r / 2.3;
}

float shape_star5 (float r, float x, float y) {
    r = mod(r - (PI_2 - PI_5), PI_5 + PI_5);
    r = abs(r - PI_5) / PI_5;
    r = mix(0.4, 1.0, r);
    return quad_oi(r);
}

vec4 ShapeStroke () {
    float dPhi = PI2 / float(STROKE_SAMPLES);
    float radius = u_radius * u_intensity;
    vec2 recSize = 1.0 / u_screen_size;
    vec4 maxRGBA = vec4(0.0);
    for (int i = 0; i < STROKE_SAMPLES; ++i) {
        float a = dPhi * float(i);
        float x = cos(a);
        float y = sin(a);
        float r = SHAPE(a, x, y) * radius;
        vec2 xy = v_xy + vec2(x, y) * r;
        vec2 uv = xy * recSize;
        maxRGBA = max(maxRGBA, texture2D(u_tex, uv));
    }
	return maxRGBA;
}

vec4 ShapeFill () {
    float dSize = (u_radius + u_radius) / float(FILL_SAMPLES);
    float radius = u_radius * u_intensity;
    vec2 recSize = 1.0 / u_screen_size;
    vec4 maxRGBA = texture2D(u_tex, v_xy * recSize);
    for (int xi = 0; xi < FILL_SAMPLES; ++xi) {
        for (int yi = 0; yi < FILL_SAMPLES; ++yi) {
            float x = u_radius - dSize * float(xi);
            float y = u_radius - dSize * float(yi);
            float a = atan(y, x);
            float X = cos(a);
            float Y = sin(a);
            float R = SHAPE(a, X, Y) * radius;
            float r = sqrt(x*x + y*y);
            if (r > R) continue;
            vec2 xy = v_xy + vec2(x, y);
            vec2 uv = xy * recSize;
            maxRGBA = max(maxRGBA, texture2D(u_tex, uv));
        }
    }
	return maxRGBA;
}

void main () {
    #ifdef USE_STROKE
    gl_FragColor = ShapeStroke();
    #else
    gl_FragColor = ShapeFill();
    #endif
}